home *** CD-ROM | disk | FTP | other *** search
/ Aminet 2 / Aminet AMIGA CDROM (1994)(Walnut Creek)[Feb 1994][W.O. 44790-1].iso / Aminet / text / dtp / t1utils.lha / t1utils / t1disasm.c < prev    next >
C/C++ Source or Header  |  1993-06-17  |  11KB  |  456 lines

  1. /* t1disasm
  2. **
  3. ** This program `disassembles' Adobe Type-1 font programs in either PFB or PFA
  4. ** format.  It produces a human readable/editable pseudo-PostScript file by
  5. ** performing eexec and charstring decryption as specified in the `Adobe Type 1
  6. ** Font Format' version 1.1 (the `black book').  There is a companion program,
  7. ** t1asm, which `assembles' such a pseudo-PostScript file into either PFB or
  8. ** PFA format.
  9. **
  10. ** Copyright (c) 1992 by I. Lee Hetherington, all rights reserved.
  11. **
  12. ** Permission is hereby granted to use, modify, and distribute this program
  13. ** for any purpose provided this copyright notice and the one below remain
  14. ** intact. 
  15. **
  16. ** author: I. Lee Hetherington (ilh@lcs.mit.edu)
  17. */
  18.  
  19. #ifndef lint
  20. static char sccsid[] =
  21.   "@(#) t1disasm.c 1.2 10:12:48 5/22/92";
  22. static char copyright[] =
  23.   "@(#) Copyright (c) 1992 by I. Lee Hetherington, all rights reserved.";
  24. #endif
  25.  
  26. /* Note: this is ANSI C. */
  27.  
  28. #include <stdio.h>
  29. #include <stdlib.h>
  30. #include <string.h>
  31. #include <ctype.h>
  32.  
  33. #ifdef MSDOS
  34. #define RB "rb"
  35. #else
  36. #define RB "r"
  37. #endif
  38.  
  39. #define BANNER   "This is t1disasm 1.2.\n"
  40. #define LINESIZE 256
  41.  
  42. #define cgetc()  cdecrypt(egetc())
  43.  
  44. typedef unsigned char byte;
  45.  
  46. static FILE *ifp = stdin;
  47. static FILE *ofp = stdout;
  48. static char line[LINESIZE];
  49. static int start_charstring = 0;
  50. static int lenIV = 4;
  51.  
  52. /* decryption stuff */
  53. static unsigned short er, cr;
  54. static unsigned short c1 = 52845, c2 = 22719;
  55.  
  56. /* This function looks for `currentfile eexec' string and returns 1 once found.
  57.    If c == 0, then simply check the status. */
  58.  
  59. static int eexec_scanner(char c)
  60. {
  61.   static char *key = "currentfile eexec\n";
  62.   static char *p = 0;
  63.  
  64.   if (!p)
  65.     p = key;
  66.  
  67.   if (c && *p) {
  68.     if (c == *p)
  69.       ++p;
  70.     else
  71.       p = key;
  72.   }
  73.   return *p == '\0';
  74. }
  75.  
  76. /* This function returns the value of a single hex digit. */
  77.  
  78. static int hexval(char c)
  79. {
  80.   if (c >= 'A' && c <= 'F')
  81.     return c - 'A' + 10;
  82.   else if (c >= 'a' && c <= 'f')
  83.     return c - 'a' + 10;
  84.   else if (c >= '0' && c <= '9')
  85.     return c - '0';
  86.   else
  87.     return 0;
  88. }
  89.  
  90. /* This function returns a single character at a time from a PFA or PFB file.
  91.    This stream is mixed ASCII and binary bytes.  For PFB files, the section
  92.    headers are removed, and \r is replaced by \n in ASCII sections.  For PFA
  93.    files, the hexdecimal data is turned into binary bytes. */
  94.  
  95. static int bgetc()
  96. {
  97.   static int first_byte = 1;
  98.   static int is_pfa = 0;
  99.   static int is_pfb = 0;
  100.   static int pfb_remaining = 0;
  101.   int c, val;
  102.  
  103.   /* is_pfa == 1 means PFA initial ASCII section
  104.      is_pfa == 2 means PFA hexadecimal section
  105.      is_pfb == 1 means PFB ASCII section
  106.      is_pfB == 2 means PFB binary section */
  107.  
  108.   c = fgetc(ifp);
  109.  
  110.   if (c == EOF)
  111.     return EOF;
  112.  
  113.   if (first_byte) {
  114.     /* Determine if this is a PFA or PFB file by looking at first byte. */
  115.     if (c == 0x80) {
  116.       is_pfb = 1;
  117.       is_pfa = 0;
  118.     } else {
  119.       is_pfb = 0;
  120.       is_pfa = 1;
  121.     }
  122.     first_byte = 0;
  123.   }
  124.  
  125.   if (is_pfb) {
  126.     /* PFB */
  127.     if (pfb_remaining == 0) {
  128.       /* beginning of block---we know c == 0x80 at this point */
  129.       switch (fgetc(ifp)) {
  130.       case 1:
  131.     is_pfb = 1;
  132.     break;
  133.       case 2:
  134.     is_pfb = 2;
  135.     break;
  136.       case 3:
  137.     return EOF;
  138.       default:
  139.     fprintf(stderr, "error: is this really a PFB file?\n");
  140.     exit(1);
  141.       }
  142.       /* get block length */
  143.       pfb_remaining = fgetc(ifp) & 0xff;
  144.       pfb_remaining |= (fgetc(ifp) & 0xff) << 8;
  145.       pfb_remaining |= (fgetc(ifp) & 0xff) << 16;
  146.       pfb_remaining |= (fgetc(ifp) & 0xff) << 24;
  147.       /* get character */
  148.       c = fgetc(ifp);
  149.       if (c == EOF)
  150.     return EOF;
  151.     }
  152.     --pfb_remaining;
  153.     /* in ASCII section change return to newline */
  154.     if (is_pfb == 1 && c == '\r')
  155.       c = '\n';
  156.     (void)eexec_scanner(c);
  157.     return c;
  158.   } else {
  159.     /* PFA */
  160.     if (is_pfa == 1) {
  161.       /* in initial ASCII */
  162.       if (eexec_scanner(c))
  163.     is_pfa = 2;
  164.       return c;
  165.     } else {
  166.       /* in hexadecimal */
  167.       while (isspace(c))
  168.     c = fgetc(ifp);
  169.       val = hexval((char)c) << 4;
  170.       val |= hexval((char)(c = fgetc(ifp)));
  171.       if (c == EOF)
  172.     return EOF;
  173.       return val;
  174.     }
  175.   }
  176. }
  177.  
  178. /* Two separate decryption functions because eexec and charstring decryption 
  179.    must proceed in parallel. */
  180.  
  181. static byte edecrypt(byte cipher)
  182. {
  183.   byte plain;
  184.  
  185.   plain = (cipher ^ (er >> 8));
  186.   er = (cipher + er) * c1 + c2;
  187.   return plain;
  188. }
  189.  
  190. static byte cdecrypt(byte cipher)
  191. {
  192.   byte plain;
  193.  
  194.   plain = (cipher ^ (cr >> 8));
  195.   cr = (cipher + cr) * c1 + c2;
  196.   return plain;
  197. }
  198.  
  199. /* This function returns 1 the first time the eexec_scanner returns 1. */
  200.  
  201. static int immediate_eexec()
  202. {
  203.   static int reported = 0;
  204.  
  205.   if (!reported && eexec_scanner(0)) {
  206.     reported = 1;
  207.     return 1;
  208.   } else {
  209.     return 0;
  210.   }
  211. }
  212.  
  213. /* This function returns a single byte at a time through (possible) eexec
  214.    decryption.  When immediate_eexec returns 1 it fires up the eexec decryption
  215.    machinery. */
  216.  
  217. static int egetc()
  218. {
  219.   static int in_eexec = 0;
  220.   int c;
  221.  
  222.   if ((c = bgetc()) == EOF)
  223.     return EOF;
  224.  
  225.   if (!in_eexec) {
  226.     if (immediate_eexec()) {
  227.       /* start eexec decryption */
  228.       in_eexec = 1;
  229.       er = 55665;
  230.       /* toss out four random bytes */
  231.       (void) edecrypt(bgetc());
  232.       (void) edecrypt(bgetc());
  233.       (void) edecrypt(bgetc());
  234.       (void) edecrypt(bgetc());
  235.     }
  236.     return c;
  237.   } else {
  238.     return edecrypt(c);
  239.   }
  240. }
  241.  
  242. /* This function returns a line of eexec decrypted characters.  A line is
  243.    terminated by length (including terminating null) greater than LINESIZE, a
  244.    newline \n, or one of the special charstring start sequences ` -| ' or
  245.    ` RD '.  The line, including the terminating newline or charstring start
  246.    sequence is put into line[].  If terminated by a charstring start sequence,
  247.    the flag start_charstring is set to 1. */
  248.  
  249. static void egetline()
  250. {
  251.   int c;
  252.   char *p = line;
  253.  
  254.   start_charstring = 0;
  255.   while (p < line + LINESIZE) {
  256.     c = egetc();
  257.     if (c == EOF)
  258.       break;
  259.     *p++ = (char) c;
  260.     if (p >= line + 4 && (strncmp(p - 4, " -| ", 4) == 0 ||
  261.               strncmp(p - 4, " RD ", 4) == 0)) {
  262.       p -= 4;
  263.       start_charstring = 1;
  264.       break;
  265.     }
  266.     if (c == '\r') {                  /* map \r to \n */
  267.       p[-1] = '\n';
  268.       break;
  269.     }
  270.     if (c == '\n')
  271.       break;
  272.   }
  273.   *p = '\0';
  274. }
  275.  
  276. /* If the line contains an entry of the form `/lenIV <num>' then set the global
  277.    lenIV to <num>.  This indicates the number of random bytes at the beginning
  278.    of each charstring. */
  279.  
  280. static void set_lenIV()
  281. {
  282.   char *p = strstr(line, "/lenIV ");
  283.  
  284.   if (p && isdigit(p[7])) {
  285.     lenIV = atoi(p + 7);
  286.   }
  287. }
  288.  
  289. /* Subroutine to output strings. */
  290.  
  291. static void output(char *string)
  292. {
  293.   fprintf(ofp, "%s", string);
  294. }
  295.  
  296. /* Subroutine to neatly format output of charstring tokens.  If token = "\n",
  297.    then a newline is output.  If at start of line (start == 1), prefix token
  298.    with tab, otherwise a space. */
  299.  
  300. static void output_token(char *token)
  301. {
  302.   static int start = 1;
  303.  
  304.   if (strcmp(token, "\n") == 0) {
  305.     fprintf(ofp, "\n");
  306.     start = 1;
  307.   } else {
  308.     fprintf(ofp, "%s%s", start ? "\t" : " ", token);
  309.     start = 0;
  310.   }
  311. }
  312.  
  313. /* Subroutine to decrypt and ASCII-ify tokens in charstring data.  First, the
  314.    length (in bytes) of the charstring is determined from line[].  Then the
  315.    charstring decryption machinery is fired up, skipping the first lenIV bytes.
  316.    Finally, the decrypted tokens are expanded into human-readable form. */
  317.  
  318. static void do_charstring()
  319. {
  320.   int l = strlen(line);
  321.   char *p = line + l - 1;
  322.   int cs_len;
  323.   int i;
  324.   int b, val;
  325.   char buf[20];
  326.  
  327.   while (p >= line && *p != ' ' && *p != '\t')
  328.     --p;
  329.   cs_len = atoi(p);
  330.  
  331.   *p = '\0';
  332.   output(line);
  333.   output(" {\n");
  334.  
  335.   cr = 4330;
  336.   for (i = 0; i < lenIV; i++, cs_len--)
  337.     (void) cgetc();
  338.  
  339.   while (cs_len > 0) {
  340.     --cs_len;
  341.     b = cgetc();
  342.     if (b >= 32) {
  343.       if (b >= 32 && b <= 246) {
  344.     val = b - 139;
  345.       } else if (b >= 247 && b <= 250) {
  346.     --cs_len;
  347.     val = (b - 247)*256 + 108 + cgetc();
  348.       } else if (b >= 251 && b <= 254) {
  349.     --cs_len;
  350.     val = -(b - 251)*256 - 108 - cgetc();
  351.       } else if (b == 255) {
  352.     cs_len -= 4;
  353.     val =  (cgetc() & 0xff) << 24;
  354.     val |= (cgetc() & 0xff) << 16;
  355.     val |= (cgetc() & 0xff) <<  8;
  356.     val |= (cgetc() & 0xff) <<  0;
  357.     /* in case an int is larger than four bytes---sign extend */
  358.     if (sizeof(int) > 4 && val & (1U << 31))
  359.       for (i = 4; i < sizeof(int); i++)
  360.         val |= 0xff << (i * 8);
  361.       }
  362.       sprintf(buf, "%d", val);
  363.       output_token(buf);
  364.     } else {
  365.       switch (b) {
  366.       case 1: output_token("hstem"); break;
  367.       case 3: output_token("vstem"); break;
  368.       case 4: output_token("vmoveto"); break;
  369.       case 5: output_token("rlineto"); break;
  370.       case 6: output_token("hlineto"); break;
  371.       case 7: output_token("vlineto"); break;
  372.       case 8: output_token("rrcurveto"); break;
  373.       case 9: output_token("closepath"); break;
  374.       case 10: output_token("callsubr"); break;
  375.       case 11: output_token("return"); break;
  376.       case 13: output_token("hsbw"); break;
  377.       case 14: output_token("endchar"); break;
  378.       case 21: output_token("rmoveto"); break;
  379.       case 22: output_token("hmoveto"); break;
  380.       case 30: output_token("vhcurveto"); break;
  381.       case 31: output_token("hvcurveto"); break;
  382.       case 12:
  383.     --cs_len;
  384.     switch (b = cgetc()) {
  385.     case 0: output_token("dotsection"); break;
  386.     case 1: output_token("vstem3"); break;
  387.     case 2: output_token("hstem3"); break;
  388.     case 6: output_token("seac"); break;
  389.     case 7: output_token("sbw"); break;
  390.     case 12: output_token("div"); break;
  391.     case 16: output_token("callothersubr"); break;
  392.     case 17: output_token("pop"); break;
  393.     case 33: output_token("setcurrentpoint"); break;
  394.     default:
  395.       sprintf(buf, "UNKNOWN_12_%d", b);
  396.       output_token(buf);
  397.       break;
  398.     }
  399.     break;
  400.       default:
  401.     sprintf(buf, "UNKNOWN_%d", b);
  402.     output_token(buf);
  403.     break;
  404.       }
  405.       output_token("\n");
  406.     }
  407.   }
  408.   output("\t}");
  409. }
  410.  
  411. int main(int argc, char **argv)
  412. {
  413.   fprintf(stderr, "%s", BANNER);
  414.  
  415.   /* possibly open input & output files */
  416.   if (argc >= 2) {
  417.     ifp = fopen(argv[1], RB);
  418.     if (!ifp) {
  419.       fprintf(stderr, "error: cannot open %s for reading\n", argv[1]);
  420.       exit(1);
  421.     }
  422.   }
  423.   if (argc >= 3) {
  424.     ofp = fopen(argv[2], "w");
  425.     if (!ofp) {
  426.       fprintf(stderr, "error: cannot open %s for writing\n", argv[2]);
  427.       exit(1);
  428.     }
  429.   }
  430.  
  431.   /* main loop---normally done when reach `mark currentfile closefile' on
  432.      output (rest is garbage). */
  433.  
  434.   for (;;) {
  435.     egetline();
  436.     if (line[0] == '\0')
  437.       break;
  438.     set_lenIV();
  439.     if (start_charstring)
  440.       do_charstring();
  441.     else
  442.       output(line);
  443.     if (strcmp(line, "mark currentfile closefile\n") == 0)
  444.       break;
  445.     }
  446.  
  447.   fclose(ifp);
  448.   fclose(ofp);
  449.  
  450.   return 0;
  451. }
  452.  
  453.  
  454.  
  455.  
  456.